//	array.h
//	Jeff Leggett
//	Dec, 1997
//
//

#ifndef ARRAY_H
#define ARRAY_H

#include <windows.h>

#define	DEFAULT_ARRAY_STEP			25

// --------------------------------------------------------------------------------
// This array stores pointers to your actual data.  It automatically grows
// as items are placed into it... 
// --------------------------------------------------------------------------------
template <class YOUR_TYPE>
class CAutoArray	
{
public:
	CAutoArray ()
	{
		step		= DEFAULT_ARRAY_STEP;	// amount of space allocated at a time...
		size		= 0;
		allocSize	= 0;
		pArray		= NULL;
	}

	virtual ~CAutoArray ()
	{
		Destroy ();
	}

	void Destroy (bool deleteData=true)
	{
		if ( deleteData )
		{
			for (DWORD i=0;i<size;i++)
			{
				YOUR_TYPE	*pElement = Get (i);

				assert ( pElement );
				delete pElement;
			}
		}
		
		if ( pArray )
			delete [] pArray;

		pArray		= NULL;
		allocSize	= 0;
		size		= 0;
	}

	void SetStep (DWORD	newStep)
	{
		step	= newStep;
	}

	virtual bool Allocate (DWORD newSize)
	{
		allocSize	= newSize;

		DWORD		*pTemp = new DWORD[allocSize];

		if ( pArray )
		{
			memcpy (pTemp, pArray, sizeof(DWORD) * size);
			delete [] pArray;
		}
		pArray	= pTemp;

		return true;
	}

	virtual bool Add (YOUR_TYPE	*element)
	{
		if ( allocSize<=size )
		{
			// time to realloc
			Allocate (allocSize+step);
		}

		size++;

		return Put (size-1, element);
	}

	virtual YOUR_TYPE *Get (DWORD	elementNbr)
	{
		if ( elementNbr>=size )
		{
			assert ( elementNbr<size );
			return NULL;
		}

		return (YOUR_TYPE*)pArray[elementNbr];
	}

	virtual bool Put (DWORD	elementNbr, YOUR_TYPE *element)
	{
		if ( elementNbr >= size )
			return false;

		pArray[elementNbr]	= (DWORD)element;

		return true;
	}

	virtual bool Delete (DWORD	elementNbr)
	{
		if ( elementNbr >= size )
			return false;

		for (DWORD index=elementNbr;index<size-1;index++)
		{
			pArray[index]	= pArray[index+1];
		}
		size--;

		return true;
	}

	virtual bool Insert (DWORD nextElementNbr, YOUR_TYPE *element)
	{
		if ( nextElementNbr >= size )
			return false;

		YOUR_TYPE	*save = Get (size-1);

		 for (DWORD index=size-1; index>nextElementNbr; index--)
		 {
			 pArray[index]	= pArray[index-1];
		 }

		 Put (nextElementNbr, element);
		 Add ( save );

		return true;
	}

	virtual DWORD GetCount()			{ return size; }


	YOUR_TYPE *		operator[] (DWORD index)
	{
		return Get (index);
	}


protected:
	DWORD		step;
	DWORD		*pArray;
	DWORD		allocSize;
	DWORD		size;
};

// circular array that makes local copy of the data added/deleted...
template <class YOUR_TYPE>
class CCircArray 
{
public:
	CCircArray ()
	{
		pArray	= NULL;
		start	= 0;
		count	= 0;
		size	= 0;
	}

	~CCircArray ()
	{
		if ( pArray )
			delete [] pArray;
	}

	bool Setup (DWORD	maxEntries)
	{
		assert ( pArray==NULL );	// only call setup once!

		pArray	= new YOUR_TYPE [ maxEntries ];
		memset (pArray,0,sizeof(YOUR_TYPE)*maxEntries);

		size	= maxEntries;

		return true;
	}

	// adds element to end of array...
	void Add (YOUR_TYPE	*pElement)
	{
		assert ( pArray );

		if ( count==size )
		{
			// need to delete oldest element and bump start up one...
			start = (start+1)%size;
			count--;
		}
		pArray[ GetIndex(count) ]	= *pElement;
		count++;
	}


	YOUR_TYPE *Get (DWORD	elementNbr)
	{
		assert ( pArray );

		if ( elementNbr >= count )
			return NULL;

		return &pArray[ GetIndex(elementNbr) ];
	}

	bool Delete (DWORD	elementNbr)
	{
		// sanity check
		if ( elementNbr >= size )
			return false;

		// check for easy (and fast) method first...
		if ( elementNbr==0 )
		{
			// deleting first item
			start	= (start+1)%size;
			count	--;
			return true;
		}

		if ( elementNbr==count-1 )
		{
			// deleting last item
			count--;
			return true;
		}

		// deleting an item in the middle...

		assert ( 0 );	// not supported yet...

		for (DWORD index=elementNbr;index<count-1;index++)
		{
			pArray[GetIndex(index)]	= pArray[GetIndex(index+1)];
		}

		count--;

		return true;
	}

	void Clear ()
	{
		count	= 0;
		start	= 0;
	}

	DWORD GetCount ()			{ return count; }
	DWORD GetMaxEntries ()		{ return size; }


	YOUR_TYPE *		operator[] (DWORD index)
	{
		return Get (index);
	}

protected:
	YOUR_TYPE	*pArray;
	DWORD		start;
	DWORD		count;
	DWORD		size;

	DWORD	GetIndex (DWORD elementNbr)
	{
		return (start + elementNbr) % size;
	}

};


//
// circular array that holds pointers to data...
//
template <class YOUR_TYPE>
class CCircArrayPtr
{
public:
	CCircArrayPtr ()
	{
		pArray	= NULL;
		start	= 0;
		count	= 0;
		size	= 0;
	}

	~CCircArrayPtr ()
	{
		if ( pArray )
		{
			Clear ();
			delete [] pArray;
		}
	}

	bool Setup (DWORD	maxEntries)
	{
		assert ( pArray==NULL );	// only call setup once!

		pArray	= new DWORD [ maxEntries ];
		memset (pArray,0,sizeof(DWORD)*maxEntries);

		size	= maxEntries;

		return true;
	}

	// adds element to end of array...
	void Add (YOUR_TYPE	*pElement)
	{
		assert ( pArray );

		if ( count==size )
		{
			// need to delete oldest element and bump start up one...
			YOUR_TYPE	*pOldest	= (YOUR_TYPE*)pArray[start];

			delete pOldest;

			start = (start+1)%size;
			count--;
		}
		pArray[ GetIndex(count) ]	= (DWORD)pElement;
		count++;
	}

	YOUR_TYPE *		operator[] (DWORD index)
	{
		return Get (index);
	}

	YOUR_TYPE *Get (DWORD	elementNbr)
	{
		assert ( pArray );

		if ( elementNbr >= count )
			return NULL;

		return (YOUR_TYPE*)pArray[ GetIndex(elementNbr) ];
	}

	void Clear ()
	{
		for (DWORD i=0;i<count;i++)
		{
			YOUR_TYPE	*pElement = Get (i);
			delete pElement;
		}
		count	= 0;
		start	= 0;
	}

	DWORD GetCount ()			{ return count; }
	DWORD GetMaxEntries ()		{ return size; }

protected:
	DWORD		*pArray;
	DWORD		start;
	DWORD		count;
	DWORD		size;

	DWORD	GetIndex (DWORD elementNbr)
	{
		return (start + elementNbr) % size;
	}

};


// used static array size.
template <class YOUR_TYPE,int ARRAY_SIZE>
class CStaticArray
{
public:
	CStaticArray ()
	{
		count	= 0;
	}

	bool Add (YOUR_TYPE		&data)
	{
		if ( count>=ARRAY_SIZE )
			return false;

		array[count]	= data;
		count++;

		return true;
	}

	bool Get (DWORD index, YOUR_TYPE *retVal)
	{
		if ( index >= count )
			return false;

		*retVal	= array[index];

		return true;
	}

	YOUR_TYPE *GetPtr ( DWORD index )
	{
		if ( index >= count )
			return NULL;

		return &array[index];
	}

	bool Update (DWORD index, YOUR_TYPE &data)
	{
		if ( index>=count )
			return false;

		array[index]	= data;

		return true;
	}

	DWORD GetCount()			{ return count; }

	void Destroy ()
	{
		count	= 0;
	}

	bool Delete (DWORD index)
	{
		if ( index>=count )
			return false;

		for (DWORD i=index;i<count-1;i++)
			array[i]	= array[i+1];

		count--;

		return true;
	}

	bool DeleteFromArray (YOUR_TYPE		&data)
	{
		for (DWORD i=0;i<count;i++)
		{
			if (array[i]==data)
			{
				Delete ( i );
				return true;
			}
		}
		return false;
	}

	YOUR_TYPE *	operator[] (DWORD index)
	{
		if ( index>= ARRAY_SIZE )
		{
			assert ( index<ARRAY_SIZE );
			return NULL;
		}

		return &array[index];
	}

	bool Insert (DWORD nextElementNbr, YOUR_TYPE element)
	{
		if ( nextElementNbr >= count )
			return false;

		YOUR_TYPE	save;
		
		Get (count-1,&save);

		 for (DWORD index=count-1; index>nextElementNbr; index--)
		 {
			 array[index]	= array[index-1];
		 }

		 Update (nextElementNbr, element);
		 
		 Add ( save );

		return true;
	}

	YOUR_TYPE *GetArray()				{ return array; }

	bool IsInArray ( YOUR_TYPE &element)
	{
		int index = GetIndex ( element );
		
		if ( index==-1 )
			return false;

		return true;
	}

	int GetIndex ( YOUR_TYPE &element )
	{
		for (DWORD i=0;i<count;i++)
		{
			if (array[i]==element)
				return i;
		}
		return -1;
	}

protected:
	YOUR_TYPE		array[ARRAY_SIZE];
	DWORD			count;
};

// ------------------------------------------------------------------
// This array stores a copy of your data.  It automatically grows
// as items are placed into it... (Just like CAutoArray, except
// CAutoArray stores pointers to your actual data...)
// ------------------------------------------------------------------
template <class YOUR_TYPE>
class CAutoCopyArray	
{
public:
	CAutoCopyArray ()
	{
		step		= DEFAULT_ARRAY_STEP;	// amount of space allocated at a time...
		size		= 0;
		allocSize	= 0;
		pArray		= NULL;
	}

	virtual ~CAutoCopyArray ()
	{
		Destroy ();
	}

	void Destroy ()
	{
		if ( pArray )
			delete [] pArray;

		pArray		= NULL;
		allocSize	= 0;
		size		= 0;
	}

	void SetStep (DWORD	newStep)
	{
		step	= newStep;
	}

	virtual bool Allocate (DWORD newSize)
	{
		allocSize	= newSize;

		YOUR_TYPE *pTemp = new YOUR_TYPE[allocSize];

		if ( pArray )
		{
			memcpy (pTemp, pArray, sizeof(YOUR_TYPE) * size);
			delete [] pArray;
		}
		pArray	= pTemp;

		return true;
	}

	virtual bool Add (YOUR_TYPE	&element)
	{
		if ( allocSize<=size )
		{
			// time to realloc
			Allocate (allocSize+step);
		}

		size++;

		return Put (size-1, element);
	}

	virtual bool Get (DWORD	elementNbr, YOUR_TYPE &value)
	{
		if ( elementNbr>=size )
		{
			assert ( elementNbr<size );
			return false;
		}

		value	= pArray[elementNbr];

		return true;
	}

	virtual bool Put (DWORD	elementNbr, YOUR_TYPE &element)
	{
		if ( elementNbr >= size )
			return false;

		pArray[elementNbr]	= element;

		return true;
	}

	virtual bool Delete (DWORD	elementNbr)
	{
		if ( elementNbr >= size )
			return false;

		for (DWORD index=elementNbr;index<size-1;index++)
		{
			pArray[index]	= pArray[index+1];
		}
		size--;

		return true;
	}

	virtual bool Insert (DWORD nextElementNbr, YOUR_TYPE &element)
	{
		if ( nextElementNbr >= size )
			return false;

		YOUR_TYPE	save;
		
		Get ( size-1, save );

		 for (DWORD index=size-1; index>nextElementNbr; index--)
		 {
			 pArray[index]	= pArray[index-1];
		 }

		 Put (nextElementNbr, element);
		 Add ( save );

		return true;
	}

	virtual DWORD GetCount()			{ return size; }

	YOUR_TYPE 	operator[] (DWORD index)
	{
		YOUR_TYPE	value;

		if ( Get ( index, value ) )
			return value;

		return 0;
	}


protected:
	DWORD		step;
	YOUR_TYPE	*pArray;
	DWORD		allocSize;
	DWORD		size;
};


#endif